﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Simple.Tools
{
	/// <summary>
	/// 
	/// </summary>
	public static class StringExtension
	{
		private static readonly RandomNumberGenerator Rng = RandomNumberGenerator.Create();
		/// <summary>
		/// 
		/// </summary>

		public static string[] HttpMediaHeader = new string[] { "application/json", "application/x-www-form-urlencoded", "text/plain" };

		/// <summary>
		/// 将路径映射成url
		/// </summary>
		/// <param name="path"></param>
		/// <returns></returns>
		public static string PathMapToUrl(this string path)
		{
			if (SimpleCheck.IsNullOrEmpty(path))
			{
				return path;
			}
			///F:\MyProject\C#\WebApp\Platform\MDT.VirtualSoftPlatform\MDT.VirtualSoftPlatform.ServiceInstance\bin\Debug\net5.0\wwwroot\resource\unity
			string[] array = path.Split(SimpleCheck.UnSprit);
			int start = IndexOf(array, SimpleCheck.Wwwroot);
			start++;
			int length = array.Length - start;
			return JoinArray(array, start, length, SimpleCheck.Sprit);
		}
		/// <summary>
		/// 将url转换路径
		/// </summary>
		/// <param name="url"></param>
		/// <returns></returns>
		public static string UrlMapToPath(this string url)
		{
			if (SimpleCheck.IsNullOrEmpty(url))
			{
				return url;
			}
			url = url.Replace(SimpleCheck.Sprit, SimpleCheck.UnSprit);
			return System.IO.Path.Combine(SimpleCheck.Wwwroot, url);
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="array"></param>
		/// <param name="target"></param>
		/// <returns></returns>
		public static int IndexOf(string[] array, string target)
		{
			if (SimpleCheck.IsNullOrEmpty(array) || string.IsNullOrEmpty(target))
			{
				return -1;
			}
			for (int i = 0; i < array.Length; i++)
			{
				if (target.Equals(array[i]))
				{
					return i;
				}
			}
			return -1;
		}
		/// <summary>
		/// 连接字符数组
		/// </summary>
		/// <param name="array"></param>
		/// <param name="start"></param>
		/// <param name="length"></param>
		/// <param name="pattern"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentOutOfRangeException"></exception>
		public static string JoinArray(string[] array, int start, int length, char pattern = ' ')
		{
			if (SimpleCheck.IsNullOrEmpty(array))
			{
				return string.Empty;
			}

			if (start >= 0 && start + length < array.Length)
			{
				throw new ArgumentOutOfRangeException("");
			}
			StringBuilder sb = new StringBuilder();
			for (int i = start; i < start + length; i++)
			{
				if (i + 1 == start + length)
				{
					sb.Append($"{array[i]}");
				}
				else
				{
					sb.Append($"{array[i]}{pattern}");
				}
			}
			return sb.ToString();
		}
		/// <summary>
		/// 将ip  转为int long,如果包含冒号将会把冒号去掉
		/// </summary>
		/// <param name="ip"></param>
		/// <returns></returns>
		public static long GetIpToInt64(this string ip)
		{
			if (SimpleCheck.IsNullOrEmpty(ip))
			{
				return 0;
			}
			if (ip.Contains(SimpleCheck.Colon))
			{
				string[] strs = ip.Split(SimpleCheck.Colon);
				foreach (var str in strs)
				{
					if (str.Contains(SimpleCheck.Dot))
						return IpToInt64(str);
				}
			}
			if (ip.Contains(SimpleCheck.Colon))
			{
				return IpToInt64(ip);
			}
			return 0;
		}


		/// <summary>
		/// 截取字符串
		/// </summary>
		/// <param name="str"></param>
		/// <param name="startStr"></param>
		/// <param name="endStr"></param>
		/// <returns></returns>
		public static string Substring(this string str, string startStr, string endStr)
		{
			if (SimpleCheck.IsNullOrEmpty(str))
			{
				return string.Empty;
			}
			if (SimpleCheck.IsNullOrEmpty(startStr) || SimpleCheck.IsNullOrEmpty(endStr))
			{
				return str;
			}
			if (str.Contains(startStr) == false && str.Contains(endStr) == false)
			{
				return string.Empty;
			}
			int start = str.IndexOf(startStr) + 2;
			int length = str.IndexOf(endStr) - start;
			return str.Substring(start, length);
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="array"></param>
		/// <param name="start"></param>
		/// <param name="length"></param>
		/// <param name="pattern"></param>
		/// <returns></returns>
		/// <exception cref="ArgumentNullException"></exception>
		/// <exception cref="ArgumentOutOfRangeException"></exception>
		public static string Substring(string[] array, int start, int length, char pattern = ' ')
		{
			if (SimpleCheck.IsNullOrEmpty(array))
			{
				throw new ArgumentNullException("空数组 array !");
			}
			if (start >= 0 && start + length < array.Length)
			{
				throw new ArgumentOutOfRangeException("");
			}
			StringBuilder sb = new StringBuilder();
			for (int i = start; i < start + length; i++)
			{
				if (i + 1 == start + length)
				{
					sb.Append($"{array[i]}");
				}
				else
				{
					sb.Append($"{array[i]}{pattern}");
				}
			}
			return sb.ToString();
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="ip"></param>
		/// <returns></returns>
		public static string IpToString(this string ip)
		{
			if (SimpleCheck.IsNullOrEmpty(ip))
			{
				return string.Empty;
			}
			if (ip.Contains(SimpleCheck.Colon))
			{
				string[] strs = ip.Split(SimpleCheck.Colon);
				foreach (var item in strs)
				{
					if (item.Contains(SimpleCheck.Dot))
					{
						return item;
					}
				}
			}
			return ip;
		}
		/// <summary>
		/// 将ip 转换成long int
		/// </summary>
		/// <param name="ip"></param>
		/// <returns></returns>
		private static long IpToInt64(string ip)
		{

			if (SimpleCheck.IsNullOrEmpty(ip))
			{
				return 0;
			}
			char[] separator = new char[] { SimpleCheck.Dot };
			string[] items = ip.Split(separator);
			if (items.Length >= 4)
			{
				return items[0].ToInt64() << 24
						| items[1].ToInt64() << 16
						| items[2].ToInt64() << 8
						| items[3].ToInt64();
			}
			return 0;
		}

		/// <summary>
		/// string to Guid
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public static Guid ToGuid(this string value)
		{
			if (SimpleCheck.IsNullOrEmpty(value))
			{
				return Guid.Empty;
			}
			if (Guid.TryParse(value, out Guid guid))
			{
				return guid;
			}
			return Guid.Empty;
		}
		/// <summary>
		/// string to datetime
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public static DateTime ToDateTime(this string value)
		{
			DateTime.TryParse(value, out DateTime time);
			return time;
		}
		/// <summary>
		/// string to TimeSpan
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public static TimeSpan ToTimeSpan(this string value)
		{
			TimeSpan.TryParse(value, out TimeSpan v);
			return v;
		}
		/// <summary>
		/// string to float
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>

		public static float ToFloat(this string value)
		{
			float.TryParse(value, out float v);
			return v;
		}

		public static short ToShort(this string value)
		{
			short.TryParse(value, out short v);
			return v;
		}
		/// <summary>
		/// string  to double
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public static double ToDouble(this string value)
		{
			double.TryParse(value, out double v);
			return v;
		}
		/// <summary>
		/// string to decimal
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public static decimal ToDecimal(this string value)
		{
			decimal.TryParse(value, out decimal v);
			return v;
		}

		/// <summary>
		/// string to int64 
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>

		public static long ToInt64(this string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return 0l;
			}
			if (long.TryParse(value, out long lvalue))
			{
				return lvalue;
			}
			return 0l;
		}

		/// <summary>
		/// string to int64 
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>

		public static int ToInt(this string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return 0;
			}
			if (int.TryParse(value, out int lvalue))
			{
				return lvalue;
			}
			return 0;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public static byte ToByte(this string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return 0;
			}
			if (byte.TryParse(value, out byte lvalue))
			{
				return lvalue;
			}
			return 0;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public static IPAddress ToIPAddress(this string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return IPAddress.None;
			}
			if (IPAddress.TryParse(value, out IPAddress lvalue))
			{
				return lvalue;
			}
			return IPAddress.None;
		}
		/// <summary>
		/// string to int array
		/// </summary>
		/// <param name="values"></param>
		/// <param name="splitSign"></param>
		/// <returns></returns>
		public static int[] ToIntArray(this string values, char splitSign)
		{
			return ToIntArray(values, splitSign.ToString());
		}
		/// <summary>
		/// string to int array
		/// </summary>
		/// <param name="values"></param>
		/// <param name="splitSign"></param>
		/// <returns></returns>
		public static int[] ToIntArray(this string values, string splitSign)
		{
			int[] result = null;
			if (SimpleCheck.IsNull(values) || SimpleCheck.IsNull(splitSign))
			{
				return result;
			}
			if (values.Contains(splitSign))
			{
				result = values.Split(splitSign).Select(t => { int.TryParse(t, out int value); return value; }).ToArray();
			}
			else
			{
				int.TryParse(values, out int value);
				result = new int[] { value };
			}
			return result;
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="values"></param>
		/// <param name="splitSign"></param>
		/// <returns></returns>
		public static Guid[] ToGuidArray(this string values, char splitSign)
		{
			return ToGuidArray(values, splitSign.ToString());
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="values"></param>
		/// <param name="splitSign"></param>
		/// <returns></returns>
		public static Guid[] ToGuidArray(this string values, string splitSign)
		{
			Guid[] result = null;
			if (SimpleCheck.IsNull(values) || SimpleCheck.IsNull(splitSign))
			{
				return result;
			}
			if (values.Contains(splitSign))
			{
				result = values.Split(splitSign).Select(t => { Guid.TryParse(t, out Guid value); return value; }).ToArray();
			}
			else
			{
				Guid.TryParse(values, out Guid value);
				result = new Guid[] { value };
			}
			return result;
		}
		/// <summary>
		/// string to string array
		/// </summary>
		/// <param name="values"></param>
		/// <param name="splitSign"></param>
		/// <returns></returns>
		public static string[] ToArray(this string values, char splitSign)
		{
			return ToArray(values, splitSign.ToString());
		}

		/// <summary>
		/// string to string array
		/// </summary>
		/// <param name="values"></param>
		/// <param name="splitSign"></param>
		/// <returns></returns>
		public static string[] ToArray(this string values, string splitSign)
		{
			string[] result = null;
			if (SimpleCheck.IsNull(values) || SimpleCheck.IsNull(splitSign))
			{
				return result;
			}
			if (values.Contains(splitSign))
			{
				result = values.Split(splitSign).Select(t => t).ToArray();
			}
			else
			{
				result = new string[] { values };
			}
			return result;
		}

		/// <summary>
		/// string to int64 array
		/// </summary>
		/// <param name="values"></param>
		/// <param name="splitSign"></param>
		/// <returns></returns>
		public static long[] ToInt64Array(this string values, char splitSign)
		{
			return ToInt64Array(values, splitSign.ToString());
		}

		/// <summary>
		/// string to int64 array
		/// </summary>
		/// <param name="values"></param>
		/// <param name="splitSign"></param>
		/// <returns></returns>
		public static long[] ToInt64Array(this string values, string splitSign)
		{
			long[] result = null;
			if (SimpleCheck.IsNull(values) || SimpleCheck.IsNull(splitSign))
			{
				return result;
			}
			if (values.Contains(splitSign))
			{
				result = values.Split(splitSign).Select(t => t.ToInt64()).ToArray();
			}
			else
			{
				result = new long[] { values.ToInt64() };
			}
			return result;
		}


		/// <summary>
		/// string to float array
		/// </summary>
		/// <param name="values"></param>
		/// <param name="splitSign"></param>
		/// <returns></returns>
		public static float[] ToFloatArray(this string values, char splitSign)
		{
			return ToFloatArray(values, splitSign.ToString());
		}

		/// <summary>
		/// string to float array
		/// </summary>
		/// <param name="values"></param>
		/// <param name="splitSign"></param>
		/// <returns></returns>
		public static float[] ToFloatArray(this string values, string splitSign)
		{
			float[] result = null;
			if (SimpleCheck.IsNull(values) || SimpleCheck.IsNull(splitSign))
			{
				return result;
			}
			if (values.Contains(splitSign))
			{
				result = values.Split(splitSign).Select(t => t.ToFloat()).ToArray();
			}
			else
			{
				result = new float[] { values.ToFloat() };
			}
			return result;
		}

		/// <summary>
		/// string to float array
		/// </summary>
		/// <param name="values"></param>
		/// <param name="splitSign"></param>
		/// <returns></returns>
		public static double[] ToDoubleArray(this string values, char splitSign)
		{
			return ToDoubleArray(values, splitSign.ToString());
		}

		/// <summary>
		/// string to float array
		/// </summary>
		/// <param name="values"></param>
		/// <param name="splitSign"></param>
		/// <returns></returns>
		public static double[] ToDoubleArray(this string values, string splitSign)
		{
			double[] result = null;
			if (SimpleCheck.IsNull(values) || SimpleCheck.IsNull(splitSign))
			{
				return result;
			}
			if (values.Contains(splitSign))
			{
				result = values.Split(splitSign).Select(t => t.ToDouble()).ToArray();
			}
			else
			{
				result = new double[] { values.ToDouble() };
			}
			return result;
		}


		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		/// <exception cref="Exception"></exception>
		public static char PathChar()
		{
			if (SimpleCheck.PlatformIsWindows())
			{
				return '\\';
			}
			else if (SimpleCheck.PlatformIsLinux())
			{
				return '/';
			}
			else
			{
				throw new Exception("PathToUrl  方法不支持该系统!");
			}
		}
		/// <summary>
		/// 根据操作系统返回路径
		/// </summary>
		/// <param name="path"></param>
		/// <returns></returns>
		/// <exception cref="Exception"></exception>
		public static string GetPath(this string path)
		{
			if (SimpleCheck.PlatformIsWindows())
			{

				return path.Replace("/", "\\");
			}
			else if (SimpleCheck.PlatformIsLinux())
			{
				return path.Replace("\\", "/");
			}

			else
			{
				throw new Exception("PathToUrl  方法不支持该系统!");
			}
		}

		/// <summary>
		/// 数字转换为字符串左边补 字符(0)
		/// </summary>
		/// <param name="value"></param>
		/// <param name="length"></param>
		/// <param name="fillValue"></param>
		/// <returns></returns>
		public static string Fill(this int value, int length, char fillValue = '0')
		{
			StringBuilder sb = new StringBuilder();

			if (value.ToString().Length == length)
			{
				sb.Append(value.ToString());
			}
			else
			{
				for (int i = value.ToString().Length; i < length; i++)
				{
					sb.Append(fillValue);
				}
				sb.Append(value.ToString());
			}
			return sb.ToString();
		}

		/// <summary>
		/// 数字转换为字符串左边补 字符(0)
		/// </summary>
		/// <param name="value"></param>
		/// <param name="length"></param>
		/// <param name="fillValue"></param>
		/// <returns></returns>
		public static string Fill(this string value, int length, char fillValue = ' ')
		{
			StringBuilder sb = new StringBuilder();
			sb.Append(value.ToString());
			for (int i = value.ToString().Length; i < length; i++)
			{
				sb.Append(fillValue);
			}
			return sb.ToString();
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="length"></param>
		/// <returns></returns>
		public static string RandomNumber(this int length)
		{
			StringBuilder str = new StringBuilder();
			Random random = new Random();
			for (int i = 0; i < length; i++)
			{
				int value = random.Next(1, 100000) % 10;
				str.Append(value);
			}
			return str.ToString();
		}

		/// <summary>
		///  从指定位置开始替换字符串
		/// </summary>
		/// <param name="value"></param>
		/// <param name="start">0表示从第一个字开始</param>
		/// <param name="end">包含最后一个字符</param>
		/// <returns></returns>
		public static string Hide(this string value, int start, int end, char c = '*')
		{
			StringBuilder sbValue = new StringBuilder();
			if (SimpleCheck.IsNullOrEmpty(value))
			{
				return string.Empty;
			}

			for (int i = 0; i < value.Length; i++)
			{
				if (i >= start && i <= end)
				{
					sbValue.Append(c);
				}
				else
				{
					sbValue.Append(value[i]);
				}
			}
			return sbValue.ToString();
		}
		/// <summary>
		/// 英文大小写数字
		/// </summary>
		/// <param name="len"></param>
		/// <returns></returns>
		public static string Random(this int len)
		{
			var chars = SimpleConstant.GetNumberAndLetter();

			StringBuilder value = new StringBuilder();
			Random rd = new Random();
			for (int i = 0; i < len; i++)
			{
				value.Append(chars[rd.Next(0, chars.Count())]);
			}
			return value.ToString();

		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="length">随机字符长度</param>
		/// <param name="useNum">默认包含小写</param>
		/// <param name="useLow">默认不包含小写</param>
		/// <param name="useUpp">默认不包含大写</param>
		/// <param name="useSpe">默认不包含特殊字符</param>
		/// <param name="custom">自定义字符串</param>
		/// <returns></returns>
		public static string Random(this int length, bool useNum = true, bool useLow = false, bool useUpp = true, bool useSpe = false, string custom = "")
		{
			if (length >= 0)
			{
				return string.Empty;
			}
			byte[] b = new byte[4];
			string? s = null;
			StringBuilder sb = new StringBuilder(custom);
			if (useNum) { sb.Append("0123456789"); }
			if (useLow) { sb.Append("abcdefghijklmnopqrstuvwxyz"); }
			if (useUpp) { sb.Append("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); }
			if (useSpe) { sb.Append("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"); }

			// 范围
			int range = sb.Length - 1;
			string value = sb.ToString();
			for (int i = 0; i < length; i++)
			{
				Rng.GetBytes(b);
				// 随机数
				double rn = BitConverter.ToUInt32(b, 0) / ((double)uint.MaxValue + 1);
				// 位置
				int position = (int)(rn * range);
				s += value.Substring(position, 1);
			}
			return s;
		}


		/// <summary>
		/// http get 参数拼接
		/// </summary>
		/// <param name="path"></param>
		/// <param name="Params"></param>
		/// <returns></returns>
		public static string GetParams(string path, object Params)
		{
			if (Params == null)
			{
				return string.Empty;
			}
			bool Is = false;
			if (!string.IsNullOrEmpty(path))
			{
				if (path[path.Length - 1] != '?')
				{
					Is = true;
				}
			}
			var str = GetParams(Params);
			if (Is)
			{
				return $"{path}?{str}";
			}
			return $"{path}{str}";
		}
		/// <summary>
		/// http Post 表单
		/// </summary>
		/// <param name="Params"></param>
		/// <returns></returns>
		public static string GetParams(object Params)
		{
			if (Params == null)
			{
				return string.Empty;
			}

			Type type = Params.GetType();
			StringBuilder sbParams = new StringBuilder();
			foreach (var item in type.GetProperties())
			{
				if (sbParams.Length != 0)
				{
					sbParams.Append("&");
				}
				sbParams.Append($"{item.Name}={item.GetValue(Params)}");
			}

			return sbParams.ToString();
		}


		/// <summary>
		/// 英文单词首写字母链接
		/// </summary>
		/// <param name="value"></param>
		/// <param name="splitSign"></param>
		/// <returns></returns>

		public static string FirstChar(this string value, char splitSign)
		{
			if (SimpleCheck.IsNullOrEmpty(value))
			{
				return string.Empty;
			}
			var array = value.ToArray(splitSign);
			StringBuilder sb = new StringBuilder();

			sb.Append(string.Join('.', array.Select(item =>
			{
				if (!SimpleCheck.IsNullOrEmpty(item))
				{
					return item[0].ToString();
				}
				else
				{
					return string.Empty;
				}
			}
			 )));

			return sb.ToString();
		}
	}
}
